home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Bug Proofing Visual Basic: A Guide to Error Handling and Prevention
(Publisher: John Wiley & Sons, Inc.)
Author(s): Rod Stephens
ISBN: 0471323519
Publication Date: 11/01/98

Search this book:
 
Previous Table of Contents Next


The following code is similar to the previous example. After loading, initializing, and unloading the form, the code displays the value contained in the txtFirstName text box. Since the form is unloaded, Visual Basic automatically reloads it. That reinitializes txtFirstName to hold whatever value it was assigned at design time. The program then displays that value instead of the name Gomez.

Even worse, Visual Basic reloads the form, so setting the frm variable to Nothing does not destroy it. It removes the program’s last reference to the form so it can no longer be used, but the graphical components of the form including its controls are still loaded even though they are not visible. If the user closes all the other forms, this one will still be running so the program will not end.

Dim frm As EmployeeForm

    Set frm = New EmployeeForm       ‘ Create the form obect.
    frm.Show                         ‘ Make the form visible.
    frm.ID = 123                     ‘ Set a public variable’s value.
    frm.txtFirstName.Text = “Gomez”  ‘ Set a control’s property.

    Unload frm                       ‘ Unload the form.

    ‘ The following line reloads the form.
    MsgBox frm.txtFirstName.Text      ‘ Display the first name text.

    Set frm = Nothing                 ‘ Remove our reference to the form.

This is a common bug. By referencing a form’s controls or properties after unloading it, the program reloads the form and keeps it hidden. This is a particularly common mistake in the code a dialog uses to unload itself.

The following code unloads its form. It then sets the form’s txtDirectoryName.Text value. That reloads the form. The txtDirectoryName.Text value may look fine to the main program, although other controls on the form will have the values they were assigned at design time. The form will be hidden but running, and that may stop the program from unloading properly.

‘ Close this form.
Private Sub mnuFileSaveAndClose_Click()
    Unload Me

    ‘ Save the current directory for the
    ‘ calling program to use.
    txtDirectoryName.Text = CurrentDirectory
End Sub

To prevent this particular error, hide the dialog instead of unloading it. That keeps the form loaded so its controls retain their values. The routine that displays the dialog should unload the form.

‘ Close this form.
Private Sub mnuFileSaveAndClose_Click()
    Me.Hide

    ‘ Save the current directory for the
    ‘ calling program to use.
    txtDirectoryName.Text = CurrentDirectory
End Sub

More generally, you can think of a form as being an object that contains public values defined in its Declarations section. It is connected to another visible object that the user sees as the form containing controls. Loading and unloading apply only to the visible object. To completely destroy the pair, the program must unload the visible object and remove all of its references to the invisible portion.

Initialize All Values

Visual Basic automatically initializes variables to default values. For the most part, those values make sense. For example, numbers are initialized to 0, strings are initialized to empty strings, and object references are initialized to Nothing.

Initialize the variables anyway. Even if you want a variable to start with its default value, initializing it makes that fact obvious. If you really want to save the tiny bit of extra time it takes to initialize the value explicitly, use a comment to emphasize the fact that you want the variable to take its default value. This makes it clear to future programmers that you did not simply forget to initialize the variable.

Dim num_employees As Integer     ‘ Initially 0.

Use All Values

If a routine does not use a value after it is set, and the value is not a parameter being returned to the calling routine, you may have a bug. If the value is not needed, it should not be calculated. If you see a situation in which a routine calculates a value but does not use it, figure out why it calculated the value. If the value is truly unnecessary, remove the calculation.

It is common to add code while initially writing a routine, and then to remove it later. A variable that was used in the initial version of the routine may no longer be necessary. This kind of unused variable should be removed from the declarations to prevent later confusion.

Another common example of this problem occurs with API functions. Many programmers assign the return status from an API function to a variable, but then they do not check the status. The following code shows a simple example using the FlashWindow API function. The variable return_status is set but never used.

Private Declare Function FlashWindow Lib “user32” _
    Alias “FlashWindow” (ByVal hwnd As Long, _
    ByVal bInvert As Long) As Long
        :
Private Sub FlashTheWindow()
Dim return_status as Long

    return_status = FlashWindow(hwnd, True)
End Sub

The program should check the status value to see if the API function succeeded. If the routine does not care whether the API call was successful, it should not assign the return status to a variable. For example, the FlashWindow API function returns a code indicating whether the window was active before the API call. It is not an error code, so, if the program does not care whether the window was active, it can safely ignore the value. In that case, it should treat FlashWindow as if it is a subroutine instead of a function.

Private Declare Function FlashWindow Lib “user32” _
    Alias “FlashWindow” (ByVal hwnd As Long, _
    ByVal bInvert As Long) As Long
        :
Private Sub FlashTheWindow()
    FlashWindow hwnd, True
End Sub

Do not assign values you never use.

Return a Value

When you write a function, make sure it always returns a value no matter what path the program takes through the code. One technique that makes this easier is to always assign the function’s value immediately before any Exit or End statement. To verify that the routine always returns a value, you just need to examine all of the Exit and End statements. If the previous statement does not assign the return value, the value is not explicitly defined.

Private Function MyFunction() As Integer
        :
If some_condition Then
    MyFunction = 1
    Exit Function
End If
    :
If some_other_condition Then
    MyFunction = 2
    Exit Function
End If
    :
MyFunction = 3
End Function

Some functions return one value for many paths of execution. You can think of this as the function’s default value. If any of several conditions occur, the function returns this value. In cases like this, you can set the function’s return value at the very beginning. Then any Exit or End statement that is not immediately preceded by an assignment statement returns the default value.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.